class Hero:
    def __init__(self, name):
        self.name = name
        self.blood = None
        self.attack = None
        self.job = None

    def __str__(self):
        info = ("Name {}".format(self.name), "blood: {}".format(self.blood),
                "attack: {}".format(self.attack), "job: {}".format(self.job))
        return '\n'.join(info)


class HeroBuilder:
    def __init__(self):
        self.hero = Hero("Monki")

    def configure_blood(self, amount):
        self.hero.blood = amount

    def configure_attack(self, amount):
        self.hero.attack = amount

    def configure_job(self, job):
        self.hero.job = job

class Game:
    def __init__(self):
        self.builder = None

    def construct_hero(self, blood, attack, job):
        self.builder = HeroBuilder()
        self.builder.configure_blood(blood)
        self.builder.configure_attack(attack),
        self.builder.configure_job(job)

    @property
    def hero(self):
        return self.builder.hero

game = Game()
game.construct_hero(5000, 200, "warrior")
hero = game.hero
print(hero)

class Dog:
    def __init__(self):
        self.name = "Dog"

    def bark(self):
        return "woof!"

class Cat:
    def __init__(self):
        self.name = "Cat"

    def meow(self):
        return "meow!"

class Adapter:
    def __init__(self, obj, **adapted_methods):
        """适配器类接收适配器方法"""
        self.obj = obj
        self.__dict__.update(adapted_methods)

    def __getattr__(self, item):
        return getattr(self.obj, item)

objects = []
dog = Dog()
cat = Cat()
objects.append(Adapter(dog, make_noise=cat.meow))
objects.append(Adapter(cat, make_noise=dog.bark))
for obj in objects:
    print("a {} goes {}".format(obj.name, obj.make_noise()))

class Publisher: # 发布者
    def __init__(self):
        self.observers = [] # 观察者

    def add(self, observer): # 加入观察者
        if observer not in self.observers:
            self.observers.append(observer)
        else:
            print("Failed to add: {}".format(observer))

    def remove(self, observer): # 移除观察者
        try:
            self.observers.remove(observer)
        except ValueError:
            print("Failed to remove: {} ".format(observer))

    def notify(self): # 调用观察者的回调
        [o.notify_by(self) for o in self.observers]

class Formatter(Publisher):

    def __init__(self, name):
        super().__init__()
        self.name = name
        self._data = 0

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, new_value):
        self._data = int(new_value)
        self.notify() # data在被合法赋值以后会执行notify

class BinaryFormatter: # 订阅者
    def notify_by(self, publisher):
        print("{}: {} has new bin data={}".format(type(self).__name__, publisher.name, bin(publisher.data)))

df = Formatter('formatter')  # 发布者
bf1 = BinaryFormatter()  # 订阅者
bf2 = BinaryFormatter()  # 订阅者
df.add(bf1) # 添加订阅者
df.add(bf2) # 添加订阅者
df.data = 3 # 设置的时候调用订阅者的notify_by
df.data = 4 # 设置的时候调用订阅者的notify_by